package cn.cutie.clotrpc.core.config;

import cn.cutie.clotrpc.core.api.*;
import cn.cutie.clotrpc.core.cluster.GrayRouter;
import cn.cutie.clotrpc.core.cluster.RandomLoadBalancer;
import cn.cutie.clotrpc.core.consumer.ConsumerBootstrap;
import cn.cutie.clotrpc.core.filter.ContextParameterFilter;
import cn.cutie.clotrpc.core.meta.InstanceMeta;
import cn.cutie.clotrpc.core.registry.clot.ClotRegistryCenter;
import cn.cutie.clotrpc.core.registry.zk.ZkRegistryCenter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;

import java.util.List;

@Slf4j
@Configuration
@Import({AppProperties.class, ConsumerProperties.class})
public class ConsumerConfig {

    @Autowired
    AppProperties appProperties;

    @Autowired
    ConsumerProperties consumerProperties;

    // ApolloChangedListener 允许java对象自动更新apollo属性
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "apollo.bootstrap", value = "enabled")
    ApolloChangedListener consumer_apolloChangedListener() {
        return new ApolloChangedListener();
    }

    // 把ConsumerBootstrap变成一个bean放在Spring里面
    @Bean
    ConsumerBootstrap consumerBootstrap(){
        return new ConsumerBootstrap();
    }

    // 已经配置了ConsumerBootstrap这个Bean，直接Autowired注入进来
    // 多个 ApplicationRunner ，先执行最外面的，这里设置一下Order值，值越小优先级越高
    @Bean
    @Order(Integer.MIN_VALUE + 1)
    public ApplicationRunner consumerBootstrapRunner(@Autowired ConsumerBootstrap consumerBootstrap){
        return x ->{
            log.info("consumerBootstrapRunner starting...");
            consumerBootstrap.start();
            log.info("consumerBootstrapRunner started...");
        };
    }

    @Bean
    public LoadBalancer<InstanceMeta> loadBalance(){
//        return LoadBalance.Default;
        return new RandomLoadBalancer();
//        return new RoundRobinLoadBalancer();
    }

    @Bean
    public Router<InstanceMeta> router(){
//        return Router.Default;
        return new GrayRouter(consumerProperties.getGrayRatio());
    }

    /**
     * 需要自动初始化和销毁
     * 与zk交互，连接初始化和停止
     * @return
     */
    @Bean(initMethod = "start", destroyMethod = "stop")
    @ConditionalOnMissingBean
    public RegistryCenter consumerRc(){
//        return new RegistryCenter.StaticRegistryCenter(List.of(servers.split(",")));
//        return new ZkRegistryCenter();
        return new ClotRegistryCenter();
    }

    @Bean
    public Filter filter(){
//        return Filter.Default;
//        return new CacheFilter();
//        return new MockFilter();
        return new ContextParameterFilter();
    }

    @Bean
    public RpcContext createContext(@Autowired Router router,
                                    @Autowired LoadBalancer loadBalancer,
                                    @Autowired List<Filter> filters) {
        RpcContext context = new RpcContext();
        context.setRouter(router);
        context.setLoadBalancer(loadBalancer);
        context.setFilters(filters);
        context.getParameters().put("app.id", appProperties.getId());
        context.getParameters().put("app.namespace", appProperties.getNamespace());
        context.getParameters().put("app.env", appProperties.getEnv());
        context.setConsumerProperties(consumerProperties);
        return context;
    }

}
